;/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;*  Copyleft (!c) 2004-2005 Div. Nucl. Med., Cyric, Tohoku Univ.    *
;*  Copyleft (!c) 2005-2011 Elseif Laboratory.                      *
;*  elseifkk@users.sf.net                                           *
;*                                                                  *
;*  All Rights Reversed.                                            *
;*                                                                  *
;*                                                                  *
;*  LICENSE AGREEMENT:                                              *
;*                                                                  *
;*  You agree that we don't agree to anything.                      *
;*                                                                  *
;*                                                                  *
;*  DISCLAIMER OF WARRANTIES:                                       *
;*                                                                  *
;*  This software is provided to you "AS IS," and the authors and   *
;*  contributors disclaim any warranty or liability obligations to  *
;*  you of any kind, implied or express, including but not limited  *
;*  to the warranties of merchantability, fitness for a particular  *
;*  purpose, and non-infringement.                                  *
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
section .data
n dd 0
a0 dd 0
a1 dd 0
b0 dd 0
b1 dd 0
x  times 8 db 0
;;; 
section .text
global cpmemw_
global cpmemr_
global cpmemd_
global cpmemb_
global cpmemwa_
global cpmemra_	
global cpmemda_
global cpmemba_
global cpmemdra_
global cmpr8_asm__
global zerod_
;;; int to real
global int1_to_real8__
global int2_to_real8__
global int4_to_real8__
global int1_to_real4__
global int2_to_real4__
global int4_to_real4__
;;;  real to real
global real4_to_real8__
global real8_to_real4__
;;; real to int
global real8_to_int1__
global real8_to_int2__	
global real8_to_int4__		
global real4_to_int1__
global real4_to_int2__	
global real4_to_int4__		
;;; int to int
global int4_to_int2__
global int4_to_int1__
global int2_to_int1__
global int1_to_int2__
global int1_to_int4__
global int2_to_int4__
;;; 
global zerocut_real4__
global zerocut_real8__
;;;
global get_minmax_int1__
global get_minmax_int2__
global get_minmax_int4__
global get_minmax_real8__
global get_minmax_real4__
;;;
global get_minmax_img_i1__
global get_minmax_img_i2__
global get_minmax_img_i4__
global get_minmax_img_r4__
global get_minmax_img_r8__				
;;; 
%assign cnv_int 0
%assign cnv_real 1
%macro int_to_real 6		; 2 word 8 qword cnv_int cnv_real
	push edi
	push esi
	push ebx
%assign _P 4*3
	mov eax, [esp+_P+4]	
	mov edx, [esp+_P+12]	; edx=dst
	mov ecx, [eax]		; ecx=n
	mov eax, [esp+_P+8]	; eax=src
	or ecx, ecx
	jz .exit_int_to_real
	;; check if cf=0
 	mov esi, [esp+_P+16]	; esi = cf
	or esi, esi
	jz .start_int_to_real
 	cmp dword [esi], 0
 	jnz .start_int_to_real_mul
 	cmp dword [esi+4], 0
 	jnz .start_int_to_real_mul
	;; 
.start_int_to_real:	
%if %1 = 1
;;; prepare to load 1 byte to st0
	xor ebx, ebx
%endif
;;; 
.do_int_to_real:
;;; load int or real to st0
%if %1 = 1
	mov bl, byte [eax]
	mov dword [n], ebx
	fild dword [n]
%else
  %if %5 = cnv_int
	fild %2 [eax]
  %else
	fld %2 [eax]
  %endif
%endif

;;; store st0 to int or real
%if %6 = cnv_real
	fstp %4 [edx]
%else
  %if %3 = 1
	fistp dword [n]
	mov ebx, [n]
	mov [edx], bl
  %else	
	fistp %4 [edx]
  %endif
%endif
;;; 
 	add eax, %1
 	add edx, %3
	dec ecx
	jnz .do_int_to_real
	jmp .exit_int_to_real
;;; 
.start_int_to_real_mul:
 	mov edi, x
 	mov ebx, [esi]
 	mov [edi], ebx
 	mov ebx, [esi+4]
 	mov [edi+4], ebx 	; x=cf to mul
	;; 
%if %1 = 1
 	xor ebx, ebx
%endif		

.do_int_to_real_mul:
;;; load int or real to st0
%if %1 = 1
 	mov bl, byte [eax]
 	mov dword [n], ebx
 	fild dword [n]
%else
   %if %5 = cnv_int
 	fild %2 [eax]
   %else
 	fld %2 [eax]
   %endif
%endif

;;; mul cf to st0
 	fmul qword [x]
		
;;; store st0 to int or real
%if %6 = cnv_real
 	fstp %4 [edx]
%else
   %if %3 = 1
 	fistp dword [n]
 	mov ebx, [n]
 	mov [edx], bl
   %else	
 	fistp %4 [edx]
   %endif
%endif  
  	add eax, %1
  	add edx, %3
 	dec ecx
 	jnz .do_int_to_real_mul
	;; 
.exit_int_to_real:	
	pop ebx
	pop esi
	pop edi
	ret
%endmacro
;;;
%assign cnv_up 0
%assign cnv_down 1 		
%macro int_to_int 6-9	; 2 word 4 dword cnv_up eax(of %2)
	push edi	; 4 dword 2 word cnv_down ax(of %2) -32767 32767 eax 
	push esi
	push ebx
%assign _P 4*3
	mov eax, [esp+_P+4]	
	mov edi, [esp+_P+12]	; dst
	mov ecx, [eax]		; n
	mov esi, [esp+_P+8]	; src
	or ecx, ecx
 	jz near .exit_int_to_int
	;;
 	sub esi, %1
 	sub edi, %3
	;; check if cf=0
  	mov ebx, [esp+_P+16]	; esi = cf
	or ebx, ebx
	jz .start_int_to_int
  	cmp dword [ebx], 0
   	jnz .start_int_to_int_mul
  	cmp dword [ebx+4], 0
   	jnz .start_int_to_int_mul
	;; 
.start_int_to_int:	
	xor eax, eax
.do_int_to_int:
  	add esi, %1
  	add edi, %3
%if %5 = cnv_up
   	movsx %6, %2 [esi]	;
  	mov %4 [edi], %6
%else
   	mov %9, %2 [esi]	;
	cmp %9, %7
	jg .next1
	mov %9, %7
	jmp .next2
.next1:
	cmp %9, %8
	jl .next2
	mov %9, %8
.next2:	
   	mov %4 [edi], %6
%endif		
	dec ecx
 	jnz .do_int_to_int
	jmp .exit_int_to_int
	;;
.start_int_to_int_mul:
 	;; 
  	mov edx, x
  	mov eax, [ebx]
  	mov [edx], eax
  	mov eax, [ebx+4]
  	mov [edx+4], eax 	; x=cf to mul
 	;; 
 	xor eax, eax	
.do_int_to_int_mul:	
   	add esi, %1
   	add edi, %3
 	;; load src int to st0
%if %1 = 1
 	mov al, [esi]
	movsx eax, al
 	mov [n], eax
 	fild dword [n]
%else
 	fild %2 [esi]
%endif
 	;; mul cf to st0
 	fmul qword [x]
 	;; 
%if %5 = cnv_up
   %if %3 = 1
 	fistp dword [n]
 	mov eax, [n]
 	mov %4 [edi], al	
   %else
 	fistp %4 [edi]	
   %endif
%else
  	fistp dword [n]
     	mov %9, %2 [n]	;
  	cmp %9, %7
   	jg .next1_mul
  	mov %9, %7
   	jmp .next2_mul
.next1_mul:
  	cmp %9, %8
   	jl .next2_mul
  	mov %9, %8
.next2_mul:	
     	mov %4 [edi], %6
%endif		
  	dec ecx
    	jnz .do_int_to_int_mul
  	;;
.exit_int_to_int:
	pop ebx
	pop esi
	pop edi
	ret
%endmacro
;;; 
;;; subroutine cpmemw(dst,src,len)
%macro cpmemx 1
	push edi
	push esi
%assign _P 4*2
 	mov eax, [esp+_P+12]
  	mov ecx, [eax]
 	mov edi, [esp+_P+4]
 	mov esi, [esp+_P+8]
.cpmem_start:	
%if %1 = 2
	rep movsw
%elif %1 = 4
  	rep movsd
%elif %1 = 1
  	rep movsb
%elif %1 = 8
	add ecx, ecx
  	rep movsd
%endif
	pop esi
	pop edi
	ret
%endmacro
;;; subroutine cpmemd(dst,src,len)
cpmemr_:
cpmemra_:
cpmemx 8
;;; 
cpmemd_:
cpmemda_:
cpmemdra_:
cpmemx 4
;;;
cpmemw_:
cpmemwa_:	
cpmemx 2
;;; 
cpmemb_:
cpmemba_:
cpmemx 1
;;; subroutine int2_to_real8(n, int2, real8)
int1_to_real8__:	
int_to_real 1, byte, 8, qword, cnv_int, cnv_real
;;; 
int2_to_real8__:	
int_to_real 2, word, 8, qword, cnv_int, cnv_real
;;; 
int4_to_real8__:	
int_to_real 4, dword, 8, qword, cnv_int, cnv_real
;;; 
int1_to_real4__:	
int_to_real 1, byte, 4, dword, cnv_int, cnv_real
;;; 
int2_to_real4__:	
int_to_real 2, word, 4, dword, cnv_int, cnv_real
;;; 
int4_to_real4__:	
int_to_real 4, dword, 4, dword, cnv_int, cnv_real
;;; 
real4_to_real8__:	
int_to_real 4, dword, 8, qword, cnv_real, cnv_real
;;; 
real8_to_real4__:	
int_to_real 8, qword, 4, dword, cnv_real, cnv_real
;;; 
real8_to_int1__:	
int_to_real 8, qword, 1, byte, cnv_real, cnv_int
;;; 
real8_to_int2__:	
int_to_real 8, qword, 2, word, cnv_real, cnv_int
;;; 
real8_to_int4__:	
int_to_real 8, qword, 4, dword, cnv_real, cnv_int
;;; 
real4_to_int1__:	
int_to_real 4, dword, 1, byte, cnv_real, cnv_int
;;; 
real4_to_int2__:	
int_to_real 4, dword, 2, word, cnv_real, cnv_int
;;; 
real4_to_int4__:	
int_to_real 4, dword, 4, dword, cnv_real, cnv_int
;;;
int1_to_int2__:
int_to_int 1, byte, 2, word, cnv_up, ax
;;;
int1_to_int4__:
int_to_int 1, byte, 4, dword, cnv_up, eax
;;;
int2_to_int4__:
int_to_int 2, word, 4, dword, cnv_up, eax
;;;
int4_to_int2__:
int_to_int 4, dword, 2, word, cnv_down, ax, -32767, 32767, eax
;;;
int4_to_int1__:
int_to_int 4, dword, 1, byte, cnv_down, al, -127, 127, eax
;;;
int2_to_int1__:
int_to_int 2, word, 1, byte, cnv_down, al, -127, 127, ax
;;;
;;; subroutine zerod(n,a)
zerod_:
	push edi
%assign _P 4*1
	mov eax, [esp+_P+4*2]	; 
	mov edi, [eax]
	mov eax, [esp+_P+4]
	mov ecx, [eax]
	xor eax, eax
	rep stosd
	pop edi	
	ret
;;; subroutine zerocut_real4(n,a)
%macro zerocut_real 1
	push edi
%assign _P 4*1
	mov edi, [esp+_P+8] 	; ptr a
	mov eax, [esp+_P+4]
	mov ecx, [eax]		; n
	or ecx, ecx
	jz .done
.do:
	dec ecx
%if %1 = 4
	mov eax, [edi+ecx*4]
%elif %1 = 8
	mov eax, [edi+ecx*8+4]
%endif
	or eax, eax
	js .cut
.next:
	or ecx, ecx
	jnz .do
	jmp .done
.cut:
%if %1 = 4
	mov dword [edi+ecx*4], 0
%elif %1 = 8
	mov dword [edi+ecx*8+4], 0
	mov dword [edi+ecx*8], 0
%endif
	jmp .next
.done:		
	pop edi	
	ret
%endmacro
;;;
zerocut_real4__:
zerocut_real 4
zerocut_real8__:
zerocut_real 8
;;;
;;; subroutine get_minmax(n,a,min,max)
;;; integer*4,intent(in)::n
;;; integer*4,intent(in)::a(n)
;;; real*8,intent(out)::min,max	
%macro get_minmax_int 1
	push edi
	push esi
	push ebx
%assign _P 4*3
	mov eax, [esp+_P+4]	; ptr n
	mov esi, [esp+_P+8]	; ptr a
	mov ecx, [eax]		; n
	;;
%if %1 = 1
	mov al, [esi] 
	mov dl, [esi]
%elif %1 = 2
	mov ax, [esi]	
	mov dx, [esi]
%elif %1 = 4	
	mov eax, [esi]		; holds max
	mov edx, [esi]		; holds min
%endif
	cmp ecx, 2
	jb .done
	dec ecx	
	;;
.do:	
%if %1 = 1
	;; 
	mov bl, [esi+ecx]	
	cmp al, bl
	jge .next1
	mov al, bl
.next1:	
	cmp dl, bl
	jle .next2
	mov dl, bl
.next2:	
	dec ecx
	jnz .do
	;; 
%elif %1 = 2
	;;
	mov bx, [esi+ecx*2]
	cmp ax, bx
	cmovl ax, bx
	cmp dx, bx
	cmovg dx, bx
	dec ecx
	jnz .do
	;; 
%elif %1 = 4
	;;
	mov ebx, [esi+ecx*4]
	cmp eax, ebx
	cmovl eax, ebx
	cmp edx, ebx
	cmovg edx, ebx
	dec ecx
	jnz .do
%endif
.done:		
	mov esi, [esp+_P+12]	; ptr min
	mov edi, [esp+_P+16]	; ptr max
%if %1 = 1
	movsx eax, al
%elif %1 = 2
	movsx eax, ax
%endif		
	mov dword [n], eax	
	fild dword [n]
	fstp qword [edi]
%if %1 = 1
	movsx edx, dl
%elif %1 = 2
	movsx edx, dx
%endif		
	mov dword [n], edx	
	fild dword [n]
	fstp qword [esi]
	;;
.exit:	
	pop ebx
	pop esi
	pop edi
	ret
%endmacro
;;;
get_minmax_img_i1__:
get_minmax_int1__:
get_minmax_int 1
get_minmax_img_i2__:
get_minmax_int2__:
get_minmax_int 2
get_minmax_img_i4__:	
get_minmax_int4__:
get_minmax_int 4	
;;;
%macro max_r4 2			; x1, x2
;;; returns x1=max(x1, x2)
	or %1, %1
	js .neg1a
	;; 
.pos1a:
	or %2, %2
	js .pos1neg2a
	;; 
.pos1pos2a:
	cmp %1, %2
	cmovb %1, %2
	jmp .exitma
	;; 
.neg1a:
	or %2, %2
	js .neg1neg2a
	;; 
.neg1pos2a:
	mov %1, %2
	jmp .exitma
	;; 
.neg1neg2a:
	cmp %1, %2
	cmova %1, %2
	jmp .exitma
	;; 
.pos1neg2a:
.exitma:	
%endmacro
;;; 
%macro min_r4 2			; x1, x2
;;; returns x1=min(x1,x2)
	or %1, %1
	js .neg1b
	;; 
.pos1b:
	or %2, %2
	js .pos1neg2b
	;; 
.pos1pos2b:
	cmp %1, %2
	cmova %1, %2
	jmp .exitmb
	;; 
.neg1b:
	or %2, %2
	js .neg1neg2b
	;; 
.neg1neg2b:
	cmp %1, %2
	cmovb %1, %2
	jmp .exitmb
	;; 
.pos1neg2b:
	mov %1, %2
	;; 
.neg1pos2b:
.exitmb:	
%endmacro
;;; 
%macro max_r8 4			; up x1, up x2, lo x1, lo x2
;;; returns up x1 = up max(x1, x2)
;;;         lo x1 = lo max(x1, x2) 
	or %1, %1
	js .neg1a
	;; 
.pos1a:
	or %2, %2
	js .pos1neg2a
	;; 
.pos1pos2a:
	cmp %1, %2
	cmovb %1, %2
	je .cmp_p1p2a
	ja .exitma
	mov %3, %4
	jmp .exitma
.cmp_p1p2a:
	cmp %3, %4
	cmovb %3, %4
	jmp .exitma
	;; 
.neg1a:
	or %2, %2
	js .neg1neg2a
	;; 
.neg1pos2a:
	mov %1, %2
	mov %3, %4
	jmp .exitma
	;; 
.neg1neg2a:
	cmp %1, %2
	cmova %1, %2
	je .cmp_n1n2a
	jb .exitma
	mov %3, %4
	jmp .exitma
.cmp_n1n2a:	
	cmp %3, %4
	cmova %3, %4
	;; 
.pos1neg2a:
.exitma:	
%endmacro
;;; 
%macro min_r8 4			; up x1, up x2, lo x1, lo x2
;;; returns up x1 = up min(x1, x2)
;;;         lo x1 = lo min(x1, x2) 
	or %1, %1
	js .neg1b
	;; 
.pos1b:
	or %2, %2
	js .pos1neg2b
	;; 
.pos1pos2b:
	cmp %1, %2
	cmova %1, %2
	je .cmp_p1p2b
	jb .exitmb
	mov %3, %4
	jmp .exitmb
	;; 
.cmp_p1p2b:
	cmp %3, %4
	cmova %3, %4
	jmp .exitmb
	;; 
.neg1b:
	or %2, %2
	js .neg1neg2b
	;;
.neg1pos2b:
	jmp .exitmb
	;; 
.neg1neg2b:
	cmp %1, %2
	cmovb %1, %2
	je .cmp_n1n2b
	ja .exitmb
	mov %3, %4
	jmp .exitmb
	;; 
.cmp_n1n2b:	
	cmp %3, %4
	cmovb %3, %4
	jmp .exitmb
	;; 
.pos1neg2b:
 	mov %1, %2
 	mov %3, %4
	;; 
.exitmb:	
%endmacro
;;;
;;; subroutine get_minmax_real8(n,a,min,max)
get_minmax_img_r8__:
get_minmax_real8__:
	push edi
	push esi
	push ebx
%assign _P 4*3
	mov eax, [esp+_P+4]	; ptr n
	mov ecx, [eax]
	mov [n], ecx		; n
	;; 
	mov esi, [esp+_P+8]	; ptr a
	;; eax:edx holds max
	mov eax, [esi+4]
	mov edx, [esi]
	;; ebx:ecx holds min
	mov ebx, [esi+4]
	mov ecx, [esi]
	;;
	cmp dword [n], 2
	jb near .done
	dec dword [n]
	;;
.do:	
	add esi, 8
	mov edi, [esi+4]
	max_r8 eax, edi, edx, dword [esi]
	min_r8 ebx, edi, ecx, dword [esi]
	dec dword [n]
	jnz .do
	;;
.done:	
	mov esi, [esp+_P+12]	; ptr min
	mov edi, [esp+_P+16]	; ptr max
	mov [edi+4], eax
	mov [edi], edx
	mov [esi+4], ebx
	mov [esi], ecx
	;; 
	pop ebx
	pop esi
	pop edi
	ret
;;;
;;; subroutine get_minmax_real8(n,a,min,max)
get_minmax_img_r4__:
get_minmax_real4__:
	push edi
	push esi
	push ebx
%assign _P 4*3
	mov eax, [esp+_P+4]	; ptr n
	mov ecx, [eax]		; n
	;; 
	mov esi, [esp+_P+8]	; ptr a
	;; eax holds max
	mov eax, [esi]
	;; edx holds min
	mov edx, [esi]
	;;
	cmp ecx, 2
	jb near .done
	dec ecx
	;;
.do:
	mov ebx, [esi+ecx*4]
   	max_r4 eax, ebx
  	min_r4 edx, ebx
	dec ecx
	jnz .do
	;;
.done:	
	mov esi, [esp+_P+12]	; ptr min
	mov edi, [esp+_P+16]	; ptr max
	mov [n], eax
	fld dword [n]
	fstp qword [edi]
	mov [n], edx
	fld dword [n]
	fstp qword [esi]
	;; 
	pop ebx
	pop esi
	pop edi
	ret
